#include <bits/types/FILE.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syslog.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <sys/stat.h>
#include <errno.h>

#define FILENAME "/tmp/out"

static int fork_daemon(void)
{
	int fd;
	pid_t pid;

	pid = fork();
	if(pid < 0){
		return -1;
	} else if(pid > 0) { 	// 父进程
		// 守护进程，需要退出父进程
		exit(0);
	} else { 				// 子进程
		fd = open("/dev/null",O_RDWR);
		if(fd < 0){
			return -1;
		}
		dup2(fd, 0);
		dup2(fd, 1);
		dup2(fd, 2);
		if(fd > 2)
			close(fd);
		// 设置当前子进程为守护进程，守护进程父进程退出后，同时pid会沿用父进程的pid，守护进程的会被init进程接管
		setsid();
		chdir("/");
		return 0;
	}

}

static FILE *fp;
static void daemon_exit(int s)
{
	printf("received a exit signal!!! \n");
	fclose(fp);
	closelog();
	exit(1);
}

int main()
{
	// 守护进程
	
	int i;

	struct sigaction siac;

	sigemptyset(&siac.sa_mask);
	siac.sa_handler = daemon_exit;
	sigaddset(&siac.sa_mask, SIGINT);
	sigaddset(&siac.sa_mask, SIGQUIT);
	sigaddset(&siac.sa_mask, SIGTERM);

	siac.sa_flags = 0; // 表示触发一个参数的指针函数

	sigaction(SIGINT, &siac, NULL);
	sigaction(SIGQUIT, &siac, NULL);
	sigaction(SIGTERM, &siac, NULL);

	// 开始写入系统日志，不是直接写入，而是通过与系统的一个syslog:守护进程进行写入
	// 通过写文件的方式，因为程序已经脱离shell，成为守护进程服务，避免使用printf向控制台输出
	openlog("fork_daemon", LOG_PID, LOG_DAEMON);

	if(fork_daemon()){
		// 子进程创建失败
		syslog(LOG_ERR, "fork_daemon process failed!");
		exit(1);
	} else {
		syslog(LOG_INFO, "fork_daemon process successed!");
	}

	fp = fopen(FILENAME, "w");
	if(fp == NULL){
		//syslog(LOG_ERR, "fopen(): %s", strerror(errno));
		exit(1);
	}
	
	syslog(LOG_INFO, "%s was opened", FILENAME);
	
	for(i = 0;;i++){
		fprintf(fp, "%d\n", i);
		fflush(fp);
		// LOG_DEBUG级别的日志不会输入到系统日志中，最小级别是LOG_INFO
		//syslog(LOG_DEBUG, "%d is writed log file", i);
		sleep(3);
	}

	fclose(fp);
	closelog();

	exit(0);
}
